package com.zyy.jomap.resolve;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.NormalAnnotationExpr;
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import com.zyy.jomap.JoMapProcessor;
import com.zyy.jomap.annotation.JoMap;
import com.zyy.jomap.annotation.JoSet;
import com.zyy.jomap.constant.Constant;
import com.zyy.jomap.constant.DebugConstant;
import com.zyy.jomap.util.CollectUtil;
import com.zyy.jomap.util.StringUtil;

import javax.tools.JavaFileObject;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.TypeVariable;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * OK--还未集成到ResolveJavaParser
 * 实现@JoSet和JoMap的解析和convert类/class的生成
 */
public class GenerateMapFile {

    private static JavaParser javaParser = new JavaParser();

    public static Map<String,List<String>> fieldClazzKeyTargetClazzListMap=new HashMap<>();

    public static Map<String, List<String>> convertClazzKeyTargetImportListMap =new HashMap<>();

    /** 循环引用次数--防止死循环 **/
    public static int loopReflectNum=1;

    public static void main(String[] args) {
        Instant nowStart = Instant.now();
//        String source="com.zyy.jomap.bo.Device";
//        String target="com.zyy.jomap.bo.DeviceBO";
//        String doTarget="com.zyy.jomap.bo.DeviceDO";
        String source="com.zyy.jomap.bo.JarDevice";
        String target="com.zyy.jomap.bo.JarDeviceBO";
        convertClazzKeyTargetImportListMap.put(source, Arrays.asList(target));
        doGenerateFile(convertClazzKeyTargetImportListMap);
        Long duration= ChronoUnit.MILLIS.between(nowStart, Instant.now());
        System.out.println("执行的毫秒数: "+duration+"ms");
    }

    /**
     * 生成JAVA文件入口--遍历解析好的JoMap.copy***对应的生成关系
     * @param sourceImportKeyTargetImportListMap  key:原类, value:目标类列表
     */
    public static void doGenerateFile(Map<String, List<String>> sourceImportKeyTargetImportListMap){
        //映射类内部的属性类型是自定义类  key:自定义类, value:映射的目标类
        Map<String,List<String>> beanFieldClazzKeyTargetClazzListMap=new HashMap<>();
        //遍历原(变量)映射列表
        for(String sourceImport:sourceImportKeyTargetImportListMap.keySet()){
            List<String> targetImportList=sourceImportKeyTargetImportListMap.get(sourceImport);
            //JoSet({"UserBO.userBo"})
            //存放JoSet注解 key:user_UserBO, value:userBo
            Map<String,String> joSetMap=new HashMap<>();
            //JoMap({"UserBO.userBo"})--双向存放key
            //存放JoMap注解 key:user_UserBO,value:userBo   key:userBo_User,value:user
            Map<String,String> joMapMap=new HashMap<>();
            //存放字段是自定义类 key:user, value:com.zyy.jomap.bo.userBO
            Map<String,String> fieldNameKeySelfClazzMap=new HashMap<>();
            List<String> sourceFieldList=new ArrayList<>();
            //属性是List且是自定义类型时记录： List<User> user;
            Map<String,Boolean> listFieldNameKeyBoolMap=new HashMap<>();
            String  sourceParentClazz=sourceImport;
            //原类及父类列表
            List<String> sourceParentClazzNameList=new ArrayList<>();
            while(sourceParentClazz!=null) {
                //父类遍历
                sourceParentClazzNameList.add(StringUtil.getClazzSimpleName(sourceParentClazz));
                sourceParentClazz = resolveFile(sourceParentClazz, joSetMap, joMapMap, fieldNameKeySelfClazzMap, sourceFieldList,listFieldNameKeyBoolMap);
            }
            //遍历目标列表
            for(String targetImport:targetImportList){
                String targetClazzName=StringUtil.getClazzSimpleName(targetImport);
                String sourceClazzName=StringUtil.getClazzSimpleName(sourceImport);
                List<String> targetFieldList=new ArrayList<>();
                String targetParentClazz=targetImport;
                //目标类及父类列表
                List<String> targetParentClazzNameList=new ArrayList<>();
                while(targetParentClazz!=null) {
                    //父类遍历
                    targetParentClazzNameList.add(StringUtil.getClazzSimpleName(targetParentClazz));
                    targetParentClazz=resolveFile(targetParentClazz, joSetMap, joMapMap, fieldNameKeySelfClazzMap, targetFieldList,listFieldNameKeyBoolMap);
                }
                String javaCode=generateFile(sourceImport,sourceFieldList,targetImport,targetFieldList,joMapMap,joSetMap,fieldNameKeySelfClazzMap,sourceParentClazzNameList,targetParentClazzNameList,listFieldNameKeyBoolMap,beanFieldClazzKeyTargetClazzListMap);
                if(DebugConstant.DEBUG) {
                    //写入java文件--测试用
                    writeFile(sourceClazzName+Constant.CONVERT_JO_CHAR+targetClazzName,javaCode);
                }else {
                    //生产java和class文件
                    doGenerateClassFile(javaCode, Constant.JOMAP_PACKAGE + "." + sourceClazzName + Constant.CONVERT_JO_CHAR + targetClazzName);
                }
            }
        }
        if(loopReflectNum<=2&&beanFieldClazzKeyTargetClazzListMap.size()>0){
            loopReflectNum++;
            doGenerateFile(beanFieldClazzKeyTargetClazzListMap);
        }

    }

    /**
     * 在target中生成源码文件并编译为class
     * @param javaCode  代码
     * @param classPackagePath  类的包路径: com.zyy.jomap.convert
     */
    public static void doGenerateClassFile(String javaCode,String classPackagePath){
        try {
            //在对应的项目target/generated-sources/annotations下生成JAVA原文件和在target/classes/包生成class字节码文件，可以使用loadClass来加载运行
            //无须自己再生成java文件和class字节码文件--不然重复存在
            //name为JAVA文件生成的路径(要含类名)
            JavaFileObject source = JoMapProcessor.processingEnvironment.getFiler().createSourceFile(
                    classPackagePath);
            Writer writer = source.openWriter();
            writer.write(javaCode);
            writer.flush();
            writer.close();
//            JoMapProcessor.sPrintMsg(classPackagePath,javaCode);
        } catch (IOException e) {
            //
        }
    }

    /**
     * 解析类是否为项目中的类还是三方jar包中的类及遍历父类
     * @param clazzPackagePath  类的包路径(含类名) com.zyy.jomap.bo.UserBO
     * @param joSetMap  JoSet注解的集合
     * @param joMapMap  JoMap注解的集合
     * @param fieldNameKeySelfClazzMap  key:属性名, value:属性对应的类
     * @param fieldList  属性列表
     * @return  返回父类的类 com.zyy.jomap.bo.UserParentBO
     */
    public static String resolveFile(String clazzPackagePath,Map<String,String> joSetMap,Map<String,String> joMapMap,Map<String,String> fieldNameKeySelfClazzMap,List<String> fieldList,Map<String,Boolean> listFieldNameKeyBoolMap){
        String sourceFileAbsPath=ResolveJava.getClazzAbsPath(clazzPackagePath);
        File sourceFile=new File(sourceFileAbsPath);
        String parentClazz=null;
        if(sourceFile.exists()){
            //项目中的实体类
            ParseResult<CompilationUnit> result = null;
            try {
                String SRC_PATH = getProjectSrcPath();
                TypeSolver reflectionType=new ReflectionTypeSolver();
                TypeSolver javaParserType=new JavaParserTypeSolver(new File(SRC_PATH));
                CombinedTypeSolver combinedTypeSolver=new CombinedTypeSolver();
                combinedTypeSolver.add(reflectionType);
                combinedTypeSolver.add(javaParserType);
                JavaSymbolSolver symbolSolver=new JavaSymbolSolver(combinedTypeSolver);
                JavaParser javaParser=new JavaParser();
                javaParser.getParserConfiguration().setSymbolResolver(symbolSolver);
                result= javaParser.parse(sourceFile);
                CompilationUnit cu=result.getResult().get();
                List<ClassOrInterfaceDeclaration> clazzList=cu.findAll(ClassOrInterfaceDeclaration.class);
                ClassOrInterfaceDeclaration clazz=clazzList.get(0);
                String clazzName=clazz.getName().toString();
                NodeList<ClassOrInterfaceType> extendList=clazz.getExtendedTypes();

                if(CollectUtil.isNotEmpty(extendList)){
                    //获取父类信息--需要遍历
                    for(ClassOrInterfaceType extendClazz:extendList){
                        parentClazz=extendClazz.asReferenceType().getElementType().resolve().asReferenceType().getQualifiedName();
                        JoMapProcessor.sPrintMsg("parent clazz",parentClazz);
                    }
                }

                Map<String,String> typeNameKeyImpoertMap=new HashMap<>();
                NodeList<ImportDeclaration> importList=cu.getImports();
                for(ImportDeclaration importDeclaration:importList){
                    String clazzImport=importDeclaration.getName().toString();
                    int lastDotIndex=clazzImport.lastIndexOf(".");
                    String typeName=clazzImport.substring(lastDotIndex+1,clazzImport.length());
                    typeNameKeyImpoertMap.put(typeName,clazzImport);
                }

                List<FieldDeclaration> fieldDeclarationList=cu.findAll(FieldDeclaration.class);
                for(FieldDeclaration fieldDeclaration:fieldDeclarationList){
                    // 该方式获取属性名有注解时不好获取 : fieldDeclaration.getChildNodes().get(1).toString();
                    String fieldName=fieldDeclaration.getVariables().get(0).getNameAsString();
                    String fieldClazz=null;
                    try {
                        //属性的类是当前项目中的类--含java自带的类
                        if(fieldDeclaration.getElementType().resolve().isReferenceType()){
                            fieldClazz=fieldDeclaration.getElementType().resolve().asReferenceType().getQualifiedName();
                            if(fieldClazz.indexOf("List")>-1){
                                fieldClazz=fieldDeclaration.getElementType().resolve().asReferenceType().typeParametersValues().get(0).asReferenceType().getQualifiedName();
                                listFieldNameKeyBoolMap.put(fieldName+Constant.UNDERLINE+fieldClazz,true);
                            }
                        }
                    }catch (Exception e){
                        //三方jar包中的类型
                        fieldClazz=typeNameKeyImpoertMap.get(fieldDeclaration.getElementType().toString());
                    }

                    if(fieldClazz!=null&&!StringUtil.checkIsJavaBaseType(fieldClazz)){
                        //不是Java类型--自定义类型
                        //device_DeviceBO, com.zyy.jomap.bo.Device
                        fieldNameKeySelfClazzMap.put(fieldName+Constant.UNDERLINE+clazzName,fieldClazz);
                        JoMapProcessor.sPrintMsg("self custom class Map",fieldNameKeySelfClazzMap.toString());
                    }

                    Optional<AnnotationExpr> joMapAnnotation=fieldDeclaration.getAnnotationByName("JoMap");
                    if(!Optional.empty().equals(joMapAnnotation)){
                        try{
                            //@JoSet({""})此种方式注解时执行该方法处理
                            List<Node> valueList;
                            valueList= ((SingleMemberAnnotationExpr) joMapAnnotation.get()).getMemberValue().getChildNodes();
                            for(Node value:valueList){
                                setJoMap(value.toString(),joMapMap,fieldName,clazzName);
                            }
                        }catch(Exception e){
                            //@JoSet(value={""})此种方式注解时执行该方法处理，此方法会把JoMap也算一个Node--需要自行解析配置的注解值
                            String valueStr=((NormalAnnotationExpr) joMapAnnotation.get()).getChildNodes().get(1).toString();
                            valueStr=valueStr.replace("value =","");
                            valueStr=valueStr.replace("{","");
                            valueStr=valueStr.replace("}","");
                            String[] annotationArr=valueStr.trim().split(",");
                            JoMapProcessor.sPrintMsg("resolve jomap valuestr",valueStr);
                            for(String annotationValue:annotationArr){
                                setJoMap(annotationValue.trim(),joMapMap,fieldName,clazzName);
                            }
                        }
                        JoMapProcessor.sPrintMsg("resolve joMapMap:",joMapMap.toString());
                    }
                    Optional<AnnotationExpr> joTargetAnnotation=fieldDeclaration.getAnnotationByName("JoSet");
                    if(!Optional.empty().equals(joTargetAnnotation)){
                        List<Node> valueList;
                        try{
                            valueList= ((SingleMemberAnnotationExpr) joTargetAnnotation.get()).getMemberValue().getChildNodes();
                            for(Node value:valueList){
                                setJoSet(value.toString(),joSetMap,fieldName);
                            }
                        }catch(Exception e){
                            //此方法会把JoMap也算一个Node--需要自行解析配置的注解值
                            String valueStr=((NormalAnnotationExpr) joTargetAnnotation.get()).getChildNodes().get(1).toString();
                            valueStr=valueStr.replace("value =","");
                            valueStr=valueStr.replace("{","");
                            valueStr=valueStr.replace("}","");
                            String[] annotationArr=valueStr.trim().split(",");
                            JoMapProcessor.sPrintMsg("resolve joSetMap valuestr",valueStr);
                            for(String annotationValue:annotationArr){
                                setJoSet(annotationValue.trim(),joSetMap,fieldName);
                            }
                        }
                        JoMapProcessor.sPrintMsg("解析的joSetMap:",joSetMap.toString());
                    }
                    fieldList.add(fieldName);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }else{
            //三方jar包的类
            try {
                JoMapProcessor.sPrintMsg("jar>>>>>>>>>>",clazzPackagePath);
                Class clazz=GenerateMapFile.class.getClassLoader().loadClass(clazzPackagePath);

                //父类
                Class superClass=clazz.getSuperclass();
                if(!superClass.equals(Object.class)){
                    parentClazz=superClass.getName();
                }

                Field[] fieldArr=clazz.getDeclaredFields();
                for(Field field:fieldArr){

                    Class fieldClazz=field.getType();
                    if(fieldClazz.equals(List.class)){
                        ParameterizedType pt = (ParameterizedType) field.getGenericType();
                        if(pt.getActualTypeArguments()[0] instanceof TypeVariable){
                            //泛型的处理
                        }else{
                            //listObjClass = (Class) pt.getActualTypeArguments()[0];
                            fieldClazz=(Class) pt.getActualTypeArguments()[0];
                            listFieldNameKeyBoolMap.put(field.getName()+Constant.UNDERLINE+fieldClazz.getName(),true);
                        }
                    }
                    if(fieldClazz!=null&&!StringUtil.checkIsJavaBaseType(fieldClazz.getName())){
                        //不是Java类型--自定义类型
                        //device_DeviceBO, com.zyy.jomap.bo.Device
                        fieldNameKeySelfClazzMap.put(field.getName()+Constant.UNDERLINE+clazz.getSimpleName(),fieldClazz.getName());
                        JoMapProcessor.sPrintMsg("self custom class Map",fieldNameKeySelfClazzMap.toString());
                    }
                    JoMap joMapAnnotation=field.getAnnotation(JoMap.class);
                    if(joMapAnnotation!=null){
                        String[] joMapAnnotationArr=joMapAnnotation.value();
                        for(String value:joMapAnnotationArr){
                            setJoMap(value,joMapMap,field.getName(),clazz.getSimpleName());
                        }
                    }
                    JoSet joTargetAnnotation=field.getAnnotation(JoSet.class);
                    if(joTargetAnnotation!=null){
                        String[] joTargetAnnotationArr=joTargetAnnotation.value();
                        for(String value:joTargetAnnotationArr){
                            setJoSet(value,joSetMap,field.getName());
                        }
                    }
                    fieldList.add(field.getName());
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return parentClazz;
    }

    /**
     * 生成文件
     * @param sourceClazz  原类
     * @param sourceFieldList  原属性列表
     * @param targetClazz  目标类
     * @param targetFieldList  目标属性列表
     * @param joMapMap  JoMap注解集合
     * @param joSetMap  JoSet注解集合
     * @param fieldSelfClazzMap 属性是自定义类型的集合
     */
    public static String generateFile(String sourceClazz,List<String> sourceFieldList,String targetClazz,List<String> targetFieldList,Map<String,String> joMapMap,Map<String,String> joSetMap,Map<String,String> fieldSelfClazzMap,List<String> sourceParentClazzNameList,List<String> targetParentClazzNameList,Map<String,Boolean> listFieldNameKeyBoolMap,Map<String,List<String>> beanFieldClazzKeyTargetClazzListMap){
        StringBuffer buffer=new StringBuffer();
        String targetClazzName=StringUtil.getClazzSimpleName(targetClazz);
        String sourceClazzName=StringUtil.getClazzSimpleName(sourceClazz);
        buffer.append("package "+ Constant.JOMAP_PACKAGE+";");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.ENTER);
        buffer.append("import com.zyy.jomap.JoMapBase;");
        buffer.append(Constant.ENTER);
        buffer.append("import "+sourceClazz+";");
        buffer.append(Constant.ENTER);
        buffer.append("import "+targetClazz+";");
        buffer.append(Constant.ENTER);
        buffer.append("import java.util.List;");
        buffer.append(Constant.ENTER);
        buffer.append("import java.util.ArrayList;");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.ENTER);
        buffer.append("public class "+sourceClazzName+Constant.CONVERT_JO_CHAR+targetClazzName+" implements JoMapBase<"+targetClazzName+","+sourceClazzName+"> {");
        buffer.append(Constant.ENTER);
        buildClazzInstant(buffer,sourceClazzName+Constant.CONVERT_JO_CHAR+targetClazzName);
        buffer.append(Constant.ENTER);
        buildCopyBeanMethod(buffer,"copyBean",sourceClazzName,sourceFieldList,targetClazzName,targetFieldList,joMapMap,joSetMap,fieldSelfClazzMap,sourceParentClazzNameList,targetParentClazzNameList,listFieldNameKeyBoolMap,beanFieldClazzKeyTargetClazzListMap);
        buildCopyBeanMethod(buffer,"copyBeanReverse",targetClazzName,targetFieldList,sourceClazzName,sourceFieldList,joMapMap,joSetMap,fieldSelfClazzMap,sourceParentClazzNameList,targetParentClazzNameList,listFieldNameKeyBoolMap,beanFieldClazzKeyTargetClazzListMap);
        buildCopyListMethod(buffer,"copyList",sourceClazzName,targetClazzName);
        buildCopyListMethod(buffer,"copyListReverse",targetClazzName,sourceClazzName);
        buffer.append(Constant.ENTER);
        buffer.append("}");
        return buffer.toString();
    }

    /**
     * 构建Bean的方法体
     * @param buffer  缓存
     * @param methodName  方法名
     * @param paramClazzName  方法入参的类名
     * @param sourceFieldList  原属性列表
     * @param returnClazzName  方法返回的类名
     * @param targetFieldList  目标属性列表
     * @param joMapMap  JoMap注解集合
     * @param joSetMap  JoSet注解集合
     * @param fieldSelfClazzMap  属性是自定义类型集合
     */
    public static void buildCopyBeanMethod(StringBuffer buffer,String methodName,String paramClazzName,List<String> sourceFieldList,String returnClazzName,List<String> targetFieldList,Map<String,String> joMapMap,Map<String,String> joSetMap,Map<String,String> fieldSelfClazzMap,List<String> sourceParentClazzNameList,List<String> targetParentClazzNameList,Map<String,Boolean> listFieldNameKeyBoolMap,Map<String,List<String>> beanFieldClazzKeyTargetClazzListMap){
        String paramName= StringUtil.firstCharToLower(paramClazzName);
        String returnVarName=StringUtil.firstCharToLower(returnClazzName);
        if(returnVarName.equals(paramName)){
            returnVarName=returnVarName+"1";
        }
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"@Override");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"public "+returnClazzName+" "+methodName+"("+paramClazzName+" "+paramName+"){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"if( "+paramName+"==null ){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.TWELVE_SPACE+"return null;");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"}");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+returnClazzName+" "+returnVarName+" = new "+returnClazzName+"();");
        buffer.append(Constant.ENTER);
        for(String targetField:targetFieldList){

            String mapField=getJoField(targetField,sourceParentClazzNameList,targetParentClazzNameList,joSetMap,joMapMap);

            //不存在的属性不set
            if (mapField == null && sourceFieldList.contains(targetField)) {
                //属性名相同的处理
                if(fieldSelfClazzMap.get(targetField+Constant.UNDERLINE+returnClazzName)==null) {
                    //Java基本类型
                    buffer.append(Constant.EIGHT_SPACE + returnVarName + ".set" + StringUtil.firstCharToUp(targetField) + "(" + paramName + ".get" + StringUtil.firstCharToUp(targetField) + "());");
                }else {
                    //自定义类型
                    String targetFieldClazz = fieldSelfClazzMap.get(targetField + Constant.UNDERLINE + returnClazzName);
                    String sourceFieldClazz = fieldSelfClazzMap.get(targetField + Constant.UNDERLINE + paramClazzName);
                    String copyBeanExpress = parseFieldConvertCopyExpress(sourceFieldClazz, targetFieldClazz,listFieldNameKeyBoolMap,targetField,beanFieldClazzKeyTargetClazzListMap);
                    buffer.append(Constant.EIGHT_SPACE + returnVarName + ".set" + StringUtil.firstCharToUp(targetField) + "(" +copyBeanExpress+"(" + paramName + ".get" + StringUtil.firstCharToUp(targetField) + "()));");
                }
                buffer.append(Constant.ENTER);
            } else if (mapField != null) {
                //属性名映射的处理--JoSet/JoMap
                if(fieldSelfClazzMap.get(targetField+Constant.UNDERLINE+returnClazzName)==null) {
                    //Java类型
                    buffer.append(Constant.EIGHT_SPACE + returnVarName + ".set" + StringUtil.firstCharToUp(targetField) + "(" + paramName + ".get" + StringUtil.firstCharToUp(mapField) + "());");
                }else {
                    //自定义类型
                    String targetFieldClazz = fieldSelfClazzMap.get(targetField + Constant.UNDERLINE + returnClazzName);
                    String sourceFieldClazz = fieldSelfClazzMap.get(mapField + Constant.UNDERLINE + paramClazzName);
                    String copyBeanExpress = parseFieldConvertCopyExpress(sourceFieldClazz, targetFieldClazz,listFieldNameKeyBoolMap,targetField,beanFieldClazzKeyTargetClazzListMap);
                    buffer.append(Constant.EIGHT_SPACE + returnVarName + ".set" + StringUtil.firstCharToUp(targetField) + "(" + copyBeanExpress+"(" + paramName + ".get" + StringUtil.firstCharToUp(mapField) + "()));");
                }
                buffer.append(Constant.ENTER);
            }
        }
        buffer.append(Constant.EIGHT_SPACE+"return "+returnVarName+";");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"}");
        buffer.append(Constant.ENTER);
    }

    /**
     * 构建List的方法体
     * @param buffer  缓存
     * @param methodName  方法名
     * @param paramClazzName  方法入参的类名
     * @param returnClazzName  方法返回的类名
     */
    public static void buildCopyListMethod(StringBuffer buffer,String methodName,String paramClazzName,String returnClazzName){
        String paramName=StringUtil.firstCharToLower(paramClazzName);
        String returnVarName=StringUtil.firstCharToLower(returnClazzName);
        if(returnVarName.equals(paramName)){
            returnVarName=returnVarName+"1";
        }
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"@Override");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"public List<"+returnClazzName+"> "+methodName+"(List<"+paramClazzName+"> "+paramName+"List){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"if( "+paramName+"List==null ){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.TWELVE_SPACE+"return null;");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"}");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"List<"+returnClazzName+"> "+returnVarName+"List = new ArrayList<>();");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"for("+paramClazzName+" "+paramName+" : "+paramName+"List){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.TWELVE_SPACE+returnClazzName+" "+returnVarName+" = "+methodName.replace("List","Bean")+"("+paramName+");");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.TWELVE_SPACE+returnVarName+"List.add("+returnVarName+");");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"}");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"return "+returnVarName+"List;");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"}");
        buffer.append(Constant.ENTER);
    }

    /**
     * 构建类的单例
     * @param buffer  代码缓存
     * @param clazzName  生成的类名
     */
    public static void buildClazzInstant(StringBuffer buffer,String clazzName){
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"private "+clazzName+"(){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"}");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"public static "+clazzName+" getInstance(){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"return InstanceHolder.HOLDER.instance;");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"}");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"private enum InstanceHolder{");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"HOLDER;");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"private "+clazzName+" instance;");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"InstanceHolder(){");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.TWELVE_SPACE+"instance=new "+clazzName+"();");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.EIGHT_SPACE+"}");
        buffer.append(Constant.ENTER);
        buffer.append(Constant.FOUR_SPACE+"}");
        buffer.append(Constant.ENTER);
    }

    /**
     * 写入文件
     * @param fileName  文件名
     * @param code  组合好的代码
     * @throws IOException
     */
    public static void writeFile(String fileName,String code) {
        String filePath=ResolveJava.getClazzAbsPath(Constant.JOMAP_PACKAGE+"."+fileName+".java");
        BufferedWriter bufferedWriter= null;
        try {
            bufferedWriter = new BufferedWriter(new FileWriter(filePath));
            bufferedWriter.write(code);
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析字段是自定义类型的转换表达式
     * 1.判断是否在fieldClazzKeyTargetClazzListMap和convertClazzTargetClazzListMap中
     * 2.没有则添加到fieldClazzKeyTargetClazzListMap中
     * @param fieldClazz  属性的自定义类
     * @param targetClazz  目标的类--转换为的目标类
     * @return
     */
    public static String parseFieldConvertCopyExpress(String fieldClazz,String targetClazz,Map<String,Boolean> listFieldNameKeyBoolMap,String fieldName,Map<String,List<String>> beanFieldClazzKeyTargetClazzListMap){
        String copyExpress=null;
        //JoMap.copyBean中解析的映射关系判断是否已经存在自定义类型的映射关系
        if(checkClazzInListMap(fieldClazz,convertClazzKeyTargetImportListMap)||checkClazzInListMap(fieldClazz,fieldClazzKeyTargetClazzListMap)){
            if(listFieldNameKeyBoolMap.get(fieldName+Constant.UNDERLINE+fieldClazz)!=null){
                copyExpress = StringUtil.getClazzSimpleName(fieldClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(targetClazz) + ".getInstance().copyList";
            }else {
                copyExpress = StringUtil.getClazzSimpleName(fieldClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(targetClazz) + ".getInstance().copyBean";
            }
            return copyExpress;
        }
        //JoMap.copyBean中解析的映射关系判断是否已经存在自定义类型的映射关系
        if(checkClazzInListMap(targetClazz,convertClazzKeyTargetImportListMap)||checkClazzInListMap(targetClazz,fieldClazzKeyTargetClazzListMap)){
            if(listFieldNameKeyBoolMap.get(fieldName+Constant.UNDERLINE+targetClazz)!=null){
                copyExpress = StringUtil.getClazzSimpleName(targetClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(fieldClazz) + ".getInstance().copyListReverse";
            }else {
                copyExpress = StringUtil.getClazzSimpleName(targetClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(fieldClazz) + ".getInstance().copyBeanReverse";
            }
            return copyExpress;
        }
        //已经解析过的自定义类型关系中判断是否已经存在自定义类型的映射关系--在映射的列表中不存在,加入当前的解析的自定义映射关系列表中
        if(CollectUtil.isNotEmpty(fieldClazzKeyTargetClazzListMap.get(fieldClazz))){
            fieldClazzKeyTargetClazzListMap.get(fieldClazz).add(targetClazz);
            if(listFieldNameKeyBoolMap.get(fieldName+Constant.UNDERLINE+fieldClazz)!=null){
                copyExpress = StringUtil.getClazzSimpleName(fieldClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(targetClazz) + ".getInstance().copyList";
            }else {
                copyExpress = StringUtil.getClazzSimpleName(fieldClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(targetClazz) + ".getInstance().copyBean";
            }
            return copyExpress;
        }
        //已经解析过的自定义类型关系中判断是否已经存在自定义类型的映射关系，不存在加入当前的解析的自定义映射关系
        if(CollectUtil.isNotEmpty(fieldClazzKeyTargetClazzListMap.get(targetClazz))){
            fieldClazzKeyTargetClazzListMap.get(targetClazz).add(fieldClazz);
            if(listFieldNameKeyBoolMap.get(fieldName+Constant.UNDERLINE+targetClazz)!=null){
                copyExpress=StringUtil.getClazzSimpleName(targetClazz)+Constant.CONVERT_JO_CHAR+StringUtil.getClazzSimpleName(fieldClazz)+".getInstance().copyListReverse";
            }else{
                copyExpress=StringUtil.getClazzSimpleName(targetClazz)+Constant.CONVERT_JO_CHAR+StringUtil.getClazzSimpleName(fieldClazz)+".getInstance().copyBeanReverse";
            }
            return copyExpress;
        }
        List<String> targetClazzList=new ArrayList<>();
        targetClazzList.add(targetClazz);
        fieldClazzKeyTargetClazzListMap.put(fieldClazz,targetClazzList);
        beanFieldClazzKeyTargetClazzListMap.put(fieldClazz,targetClazzList);
        if(listFieldNameKeyBoolMap.get(fieldName+Constant.UNDERLINE+fieldClazz)!=null){
            copyExpress = StringUtil.getClazzSimpleName(fieldClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(targetClazz) + ".getInstance().copyList";
        }else {
            copyExpress = StringUtil.getClazzSimpleName(fieldClazz) + Constant.CONVERT_JO_CHAR + StringUtil.getClazzSimpleName(targetClazz) + ".getInstance().copyBean";
        }
        return copyExpress;
    }

    /**
     * 检查类是否已经解析过--已经解析过不再加入listMap中
     * @param clazz  属性的自定义类
     * @param listMap
     * @return  true:已经解析过, false:还未解析过需要存入listMap中--再次遍历
     */
    public static Boolean checkClazzInListMap(String clazz,Map<String,List<String>> listMap){
        List<String> targetClazzList=listMap.get(clazz);
        if(CollectUtil.isNotEmpty(targetClazzList)){
            for(String targetClazzItem:targetClazzList){
                if(targetClazzItem.equals(clazz)){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 遍历类及父类列表判断属性对应的JoSet和JoMap中的映射名
     * @param fieldName  属性名
     * @param sourceClazzNameList  原的类及父类列表
     * @param targetClazzNameList  目标的类及父类列表
     * @return null:未找到映射名, user:找到的映射名
     */
    public static String getJoField(String fieldName,List<String> sourceClazzNameList,List<String> targetClazzNameList,Map<String,String> joSetMap,Map<String,String> joMapMap){
        String mapField=null;
        for(int i=0;i<sourceClazzNameList.size();i++){
            for(int j=i;j<targetClazzNameList.size();j++){
                if(joSetMap.get(fieldName+Constant.UNDERLINE+sourceClazzNameList.get(i))!=null){
                    mapField=joSetMap.get(fieldName+Constant.UNDERLINE+sourceClazzNameList.get(i));
                }else if(joSetMap.get(fieldName+Constant.UNDERLINE+ targetClazzNameList.get(j))!=null){
                    mapField=joSetMap.get(fieldName+Constant.UNDERLINE+ targetClazzNameList.get(j));
                }else if(joMapMap.get(fieldName+Constant.UNDERLINE+sourceClazzNameList.get(i))!=null){
                    mapField=joMapMap.get(fieldName+Constant.UNDERLINE+sourceClazzNameList.get(i));
                }else if(joMapMap.get(fieldName+Constant.UNDERLINE+targetClazzNameList.get(j))!=null){
                    mapField=joMapMap.get(fieldName+Constant.UNDERLINE+targetClazzNameList.get(j));
                }
                if(mapField!=null){
                    break;
                }
            }
            if(mapField!=null){
                break;
            }
        }
        return mapField;
    }

    /**
     * 存储JoMap映射
     * @param annotationValue
     * @param joMapMap
     * @param fieldName
     * @param clazzName
     */
    public static void setJoMap(String annotationValue,Map<String,String> joMapMap,String fieldName,String clazzName){
        String[] valueArr;
        if(annotationValue.startsWith("\"")){
            valueArr=annotationValue.substring(1,annotationValue.length()-1).split("\\.");
        }else{
            valueArr=annotationValue.split("\\.");
        }
        if(valueArr.length>1){
            if(joMapMap.get(valueArr[1]+Constant.UNDERLINE+valueArr[0])==null){
                joMapMap.put(fieldName+Constant.UNDERLINE+valueArr[0],valueArr[1]);
                joMapMap.put(valueArr[1]+Constant.UNDERLINE+clazzName,fieldName);
            }
        }
    }

    /**
     * 存储JoSet映射
     * @param annotationValue
     * @param joSetMap
     * @param fieldName
     */
    public static void setJoSet(String annotationValue,Map<String,String> joSetMap,String fieldName){
        String[] valueArr;
        if(annotationValue.startsWith("\"")){
            valueArr=annotationValue.substring(1,annotationValue.length()-1).split("\\.");
        }else{
            valueArr=annotationValue.split("\\.");
        }
        if(valueArr.length>1){
            joSetMap.put(fieldName+Constant.UNDERLINE+valueArr[0],valueArr[1]);
        }
    }

    /**
     * 获取项目的src/main/java绝对路径
     * @return
     */
    public static String getProjectSrcPath(){
        if(DebugConstant.DEBUG) {
            String projectPath = System.getProperty("user.dir");
            projectPath = projectPath.replace("\\", Constant.SLASH);
            projectPath = projectPath + Constant.SLASH + DebugConstant.PROJECT_NAME + Constant.SLASH;
            return projectPath + Constant.SRC_MAIN_JAVA_PATH;
        }else{
            return JoMapProcessor.projectDirAbsPath;
        }
    }

}
